// mark这个文件是对 provider和inject的封装
// 不用每次都定义很多provider / inject了
// 直接外层调用即可
import {
    InjectionKey,
    provide,
    inject,
    reactive,
    readonly as defineReadonly,
    // defineComponent,
    UnwrapRef,
} from 'vue';


export interface CreateContextOptions {
    readonly?: boolean;
    createProvider?: boolean;
    native?: boolean;
}

type ShallowUnwrap<T> = {
    [P in keyof T]: UnwrapRef<T[P]>;
};



// T 是需要创建并传递的数据类型,注意这里面没有定义component,の下一层会用到,具体使用可以参加useFormContext
export function createContext<T>(
    context: any,
    key: InjectionKey<T> = Symbol(),
    
    options: CreateContextOptions = {},
) {
    const { readonly = true, createProvider = false, native = false } = options;
    const state = reactive(context);
    const provideData = readonly ? defineReadonly(state) : state;
    //可以这么理解:否是创建容器？否就继续. 感觉不如三元判断舒服
    !createProvider && provide(key, native ? context : provideData);  
    return {
        state,
    };
}

export function useContext<T>(key: InjectionKey<T>, native?: boolean): T;
export function useContext<T>(key: InjectionKey<T>, defaultValue?: any, native?: boolean): T;

/**
 * InjectionKey<>  —— symbol 的泛型版本,T是要传递的数据类型
 * 其他文件导入这个即可
 * 好处:可以把需要向下全局共享的内容接口化
 * 
 * 使用: 
 * 定义 interface T
 * 生成 key
 * 通过key调用生成的context
 * 
 * 在组件中直接如下使用:
 * ① createFormContext({定义T的对象实例 })
 * ② useFormContext()
*/
export function useContext<T>(
    key: InjectionKey<T> = Symbol(),
    defaultValue?: any,
): ShallowUnwrap<T> {
    return inject(key, defaultValue || {});
}


